using System;
using System.Reflection;
using Cysharp.Threading.Tasks;
using Google.Protobuf;
using MoonFramework.Scripts.Mono;
using MoonFramework.Scripts.Pool;
using MoonFramework.Scripts.Tool.DataSaveManager;
using MoonFramework.Scripts.Tool.System.Setting;
using MoonFramework.Template;
using Object = UnityEngine.Object;

namespace MoonFramework.Scripts.Tool
{
    public static class MoonExtension
    {
        #region 通用模块

        #region 特性获取扩展方法

        public static T GetAttribute<T>(this Type type) where T : global::System.Attribute
        {
            return type.GetCustomAttribute<T>();
        }

        public static T GetAttribute<T>(this object obj) where T : global::System.Attribute
        {
            return obj.GetType().GetCustomAttribute<T>();
        }

        public static T GetAttribute<T>(this object obj, Type type) where T : global::System.Attribute
        {
            return type.GetCustomAttribute<T>();
        }

        #endregion 特性获取扩展方法

        /// <summary>
        ///     数组相等对比
        /// </summary>
        public static bool ArrayEquals(this object[] objs, object[] other)
        {
            if (other == null || objs.GetType() != other.GetType()) return false;
            if (objs.Length == other.Length)
            {
                for (var i = 0; i < objs.Length; i++)
                    if (!objs[i].Equals(other[i]))
                        return false;
            }
            else
            {
                return false;
            }

            return true;
        }

        #endregion

        #region 资源管理模块
        
        #region 将对象从对象池中拿出

        public static async UniTask<Object> MoonGameObjGetPool(this object obj, string address,
            Action<Object> action = null)
        {
            return await GameObjPoolManager.Instance.PopAsync<Object>(address, action);
        }
        
        public static T MoonObjGetPool<T>(this object obj, Func<T> _fun) where T : class
        {
            return ObjPoolManager.Instance.Pop( _fun);
        }
        
        public static async UniTask<T> MoonObjGetPoolAsync<T>(this object obj, Func<UniTask<T>> _fun)
            where T : class
        {
            return await ObjPoolManager.Instance.PopAsync(_fun);
        }

        #endregion 将对象从对象池中拿出

        /// <summary>
        ///     GameObj放入对象池
        /// </summary>
        public static void MoonGameObjPushPool(this Object obj, string name)
        {
            GameObjPoolManager.Instance.Push(name, obj);
        }
        
        public static void MoonGameObjPushPool(this Object obj)
        {
            GameObjPoolManager.Instance.Push(obj.name, obj);
        }
        
        public static void MoonObjPushPool(this object obj)
        {
            ObjPoolManager.Instance.Push(obj);
        }
        #endregion

        #region Mono

        public static void SendUpdateEvent(this object obj, Action _fun)
        {
            MonoManager.Instance.SendUpdateEvent(_fun);
        }

        public static void RemoveUpdateEvent(this object obj, Action _fun)
        {
            MonoManager.Instance.RemoveUpdateEvent(_fun);
        }

        #endregion 提供给外部 用于外部帧更新/移除事件函数

        #region 配置管理模块

        public static T GetConfig<T>(this string configName, int id) where T : BaseConfig
            => ConfigManager.Instance.GetConfig<T>(configName, id );

        #endregion
        
        #region Net网络相关扩展

        public static void Writing(this byte[] _, ref byte[] message, int messageId)
        {
            var index = 0;
            var fullMessage = new byte[8 + message.Length];

            BitConverter.GetBytes(messageId).CopyTo(fullMessage, index);
            index += sizeof(int);

            BitConverter.GetBytes(message.Length).CopyTo(fullMessage, index);
            index += sizeof(int);

            message.CopyTo(fullMessage, index);

            message = fullMessage;
        }

        public static T Deserialize<T>(this byte[] bytes) where T : class, IMessage, new()
        {
            return SaveManager.Deserialize<T>(bytes);
        }

        public static byte[] Serialize<T>(this T message) where T : IMessage
        {
            return message.ToByteArray();
        }

        #endregion Net网络相关扩展
    }
}